package com.marisfrolg.config;

import com.marisfrolg.model.MyUserDetails;
import com.marisfrolg.service.MyUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.builders.JdbcClientDetailsServiceBuilder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.*;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

@Configuration

//开启oauth2,auth server模式
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Resource
    private DataSource dataSource;

    //配置客户端
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

//
//
        JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource);
        jdbcClientDetailsService.setPasswordEncoder(passwordEncoder);

        ClientDetailsService clientDetailsService = new JdbcClientDetailsServiceBuilder().dataSource(dataSource).passwordEncoder(passwordEncoder).build();
        clients.withClientDetails(clientDetailsService);

//
//        clients.inMemory()
//                //client的id和密码
//                .withClient("client1")
//                .secret(passwordEncoder.encode("123123"))
//                //给client一个id,这个在client的配置里要用的
//                .resourceIds("order_api")
//                .authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token")
//                //http://localhost:3001/oauth/authorize?response_type=code&client_id=client1&redirect_uri=http://www.baidu.com&scope=scope1
//
//                .authorizedGrantTypes("authorization_code","refresh_token")
//                //授权的范围,每个resource会设置自己的范围.
//                .scopes("scope1", "scope2")
//                .accessTokenValiditySeconds(300)
//                //这个是设置要不要弹出确认授权页面的.
//                .autoApprove(true)
//
//                //这个相当于是client的域名,重定向给code的时候会跳转这个域名
//                .redirectUris("http://www.baidu.com")
//
//
//                //密码模式
//                .and()
//                .withClient("ods").secret(passwordEncoder.encode("123123"))
//                .resourceIds("order_api").authorizedGrantTypes("password","refresh_token")
//                .accessTokenValiditySeconds(300)
//                .scopes("scope1").autoApprove(true)
//
//
//                //客户端模式
//                .and()
//                .withClient("ods_system").secret(passwordEncoder.encode("123123"))
//                .resourceIds("order_api").authorizedGrantTypes("client_credentials","refresh_token").scopes("scope1")
//                .accessTokenValiditySeconds(300)
//                //客户端模式可以根据authorities校验权限
//                .authorities("order-createOrder")
//                .autoApprove(true);

    }


    @Autowired
    private ClientDetailsService clientDetailsService;

    @Resource
    private MyUserDetailService MyUserDetailService;

    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;

    @Autowired
    private JwtTokenEnhancer jwtTokenEnhancer;

    @Autowired
    private TokenStore tokenStore;


    //配置token管理服务
    @Bean
    public AuthorizationServerTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setClientDetailsService(clientDetailsService);
        defaultTokenServices.setSupportRefreshToken(true);

        //配置token的存储方法
        defaultTokenServices.setTokenStore(tokenStore);
        defaultTokenServices.setAccessTokenValiditySeconds(300);
        defaultTokenServices.setRefreshTokenValiditySeconds(1500);

        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        List<TokenEnhancer> tokenEnhancers = new ArrayList<>();
        tokenEnhancers.add(jwtTokenEnhancer);
        tokenEnhancers.add(jwtAccessTokenConverter);
        tokenEnhancerChain.setTokenEnhancers(tokenEnhancers);
        defaultTokenServices.setTokenEnhancer(tokenEnhancerChain);

        return defaultTokenServices;
    }

    //密码模式才需要配置,认证管理器
    @Autowired
    private AuthenticationManager authenticationManager;

    //把上面的各个组件组合在一起
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager)//认证管理器
                .authorizationCodeServices(new InMemoryAuthorizationCodeServices())//授权码管理
                .tokenServices(tokenServices())//token管理
                .allowedTokenEndpointRequestMethods(HttpMethod.POST)
                .tokenGranter(tokenGranter(endpoints));
    }

    //配置哪些接口可以被访问
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.tokenKeyAccess("permitAll()")///oauth/token_key公开
                .checkTokenAccess("permitAll()")///oauth/check_token公开
                .allowFormAuthenticationForClients();//允许表单认证
    }

    private TokenGranter tokenGranter(AuthorizationServerEndpointsConfigurer endpoints) {

        // endpoints.getTokenGranter() 获取SpringSecurity OAuth2.0 现有的授权类型
        List<TokenGranter> granters = new ArrayList<TokenGranter>(Collections.singletonList(endpoints.getTokenGranter()));

        // 构建短信验证授权类型
        SmsCodeTokenGranter smsCodeTokenGranter = new SmsCodeTokenGranter(endpoints.getTokenServices(), endpoints.getClientDetailsService(),
                endpoints.getOAuth2RequestFactory(), MyUserDetailService);
        // 向集合中添加短信授权类型
        granters.add(smsCodeTokenGranter);
        // 返回所有类型
        return new CompositeTokenGranter(granters);
    }
}